package com.xs.micro.tool.domain.business;

import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.xs.micro.tool.config.prop.AppPropertiesConfig;
import com.xs.micro.tool.config.prop.sub.BankInfoConfig;
import com.xs.micro.tool.config.prop.sub.IdCardBeginNoConfig;
import com.xs.micro.tool.domain.pojo.contants.RandomPeopleInfoDataContants;
import com.xs.micro.tool.domain.pojo.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Random;

/**
 * 生成随机个人信息业务
 *
 * @author guochaohui
 */
@Component
@Slf4j
public class RandomPeopleInfoBusiness {

    private final Random random = new Random();

    private final int checkBankBinMaxCount = 1000;

    @Autowired
    private AppPropertiesConfig appPropertiesConfig;

    public List<BankInfoConfig> getBankInfoList() {
        return appPropertiesConfig.getBankInfoList();
    }

    public List<IdCardBeginNoConfig> getProvinceList() {
        return appPropertiesConfig.getIdCardBeginNoProvinceList();
    }

    public List<IdCardBeginNoConfig> getCityList(String provinceCode) {
        return appPropertiesConfig.getIdCardBeginNoCityMap().get(StringUtils.left(provinceCode, RandomPeopleInfoDataContants.PROVINCE_CODE_PREFIX_LENGTH));
    }

    public List<IdCardBeginNoConfig> getCountyList(String cityCode) {
        return appPropertiesConfig.getIdCardBeginNoCountyMap().get(StringUtils.left(cityCode, RandomPeopleInfoDataContants.CITY_CODE_PREFIX_LENGTH));
    }

    /**
     * 生成随机个人信息
     *
     * @param generateParam
     * @return
     */
    public List<GenerateRandomPeopleInfoVO> generateRandomPeopleInfo(GenerateRandomPeopleInfoParamVO generateParam) {
        List<GenerateRandomPeopleInfoVO> list = Lists.newArrayList();
        for (int i = 0; i < generateParam.getGenerateCount(); i++) {
            int gender = generateParam.getGender().intValue() == -1 ? random.nextInt(2) : generateParam.getGender();
            String name = generateRandomPeopleName(gender);
            IdCardInfoVO idCardInfo = generateRandomIdCardInfo(generateParam.getIdCardNoProvinceCode(), generateParam.getIdCardNoCityCode(), generateParam.getIdCardNoCountyCode(), gender, null);
            String mobile = generateRandomMobile();
            for (int j = 0; j < generateParam.getBankCardNoCountOfEachPeople(); j++) {
                BankCardInfoVO bankCardInfo = generateRandomBankCardInfo(generateParam.getBankCardType());
                GenerateRandomPeopleInfoVO vo = new GenerateRandomPeopleInfoVO();
                vo.setPeopleName(name);
                vo.setPeopleGender(gender == 1 ? "男" : "女");
                vo.setPeopleIdCardNo(idCardInfo.getIdCardNo());
                vo.setPeopleAge(idCardInfo.getAge());
                vo.setPeopleBirthday(DateFormatUtils.format(idCardInfo.getBirthday(), "yyyy-MM-dd"));
                vo.setPeopleBankCard(bankCardInfo);
                vo.setPeopleMobile(generateParam.getMobileOfEachPeopleIsTheSame() ? mobile : generateRandomMobile());
                vo.setIdCardAreaInfo(idCardInfo.getAreaInfo());
                list.add(vo);
            }
        }
        return list;
    }

    /**
     * 生成随机银行卡信息
     *
     * @return
     */
    public BankCardInfoVO generateRandomBankCardInfo(Integer bankCardType) {
        BankInfoConfig bankInfo = bankCardType == -1 ? (BankInfoConfig) getRandomObject(appPropertiesConfig.getBankInfoList()) : appPropertiesConfig.getBankInfoList().get(bankCardType);
        int checkBankBinCount = 0;
        while (checkBankBinMaxCount > checkBankBinCount) {
            checkBankBinCount++;
            StringBuilder sb = new StringBuilder();
            sb.append(bankInfo.getBeginNo());
            sb.append(RandomStringUtils.randomNumeric(6));
            sb.append(RandomStringUtils.randomNumeric(6));
            sb.append(RandomStringUtils.randomNumeric(6));
            String cardNo = StringUtils.left(sb.toString(), bankInfo.getNoLength());
            if (!checkBankBin(cardNo)) {
                continue;
            }
            BankCardInfoVO bankCardInfoVO = new BankCardInfoVO();
            bankCardInfoVO.setCardNo(cardNo);
            bankCardInfoVO.setCnName(bankInfo.getCnName());
            bankCardInfoVO.setEnName(bankInfo.getEnName());
            return bankCardInfoVO;
        }
        return null;
    }

    private boolean checkBankBin(String bankCardNo) {
        int checkSum = 0;
        for (int i = bankCardNo.length() - 1; i > 0; i--) {
            int b = Integer.valueOf(StringUtils.substring(bankCardNo, i - 1, i));
            if (i % 2 == 1) {
                checkSum += b * 2;
                if (b * 2 > 9) {
                    checkSum -= 9;
                }
            } else {
                checkSum += b;
            }
        }
        return checkSum % 10 == 0;
    }

    /**
     * 生成随机手机号
     *
     * @return
     */
    public String generateRandomMobile() {
        StringBuilder sb = new StringBuilder();
        sb.append(getRandomObject(appPropertiesConfig.getMobileInfoBeginNoList()));
        sb.append(RandomStringUtils.randomNumeric(4));
        sb.append(RandomStringUtils.randomNumeric(4));
        return sb.toString();
    }

    /**
     * 生成随机人名
     *
     * @param gender 0女、1男
     * @return
     */
    public String generateRandomPeopleName(int gender) {
        List<String> otherNameList = gender == 1 ? appPropertiesConfig.getMaleNameList() : appPropertiesConfig.getFemaleNameList();
        StringBuilder sb = new StringBuilder();
        sb.append(getRandomObject(appPropertiesConfig.getLastNameList()));
        sb.append(getRandomObject(otherNameList));
        if (random.nextBoolean()) {
            sb.append(getRandomObject(otherNameList));
        }
        return sb.toString();
    }

    /**
     * 生成随机身份证件号
     *
     * @param provinceCode 省code
     * @param cityCode     市code
     * @param countyCode   区code
     * @param gender       0女、1男
     * @param age          年龄，不传随机生成
     * @return
     */
    public IdCardInfoVO generateRandomIdCardInfo(String provinceCode, String cityCode, String countyCode, int gender, Integer age) {
        Date birthday = null;
        if (age == null) {
            birthday = generateRandomAdultBirthday();
        } else {
            birthday = generateBirthday(age);
        }
        IdCardAreaInfoVO areaInfo = generateIdCardNoAreaCode(provinceCode, cityCode, countyCode);
        int iCode = random.nextInt(1000);
        if ((gender == 1 && iCode % 2 == 0) || (gender == 0 && iCode % 2 == 1)) {
            iCode++;
        }
        String code = StringUtils.leftPad(String.valueOf(iCode), 3, "0");

        StringBuilder sb = new StringBuilder();
        sb.append(areaInfo.getCounty().getCode());
        sb.append(DateFormatUtils.format(birthday, "yyyyMMdd"));
        sb.append(code);
        sb.append(generateIdCardTrailingNo(sb.toString()));

        String idCardNo = sb.toString();


        IdCardInfoVO idCardInfo = new IdCardInfoVO();
        idCardInfo.setIdCardNo(idCardNo);
        idCardInfo.setBirthday(birthday);
        idCardInfo.setGender(gender);
        idCardInfo.setAge(calcAge(birthday));
        idCardInfo.setAreaInfo(areaInfo);
        return idCardInfo;
    }

    /**
     * 生成身份证件号前6位
     *
     * @param provinceCode
     * @param cityCode
     * @param countyCode
     * @return
     * @author guochaohui
     * @date 2022-04-07 上午 11:35
     */
    private IdCardAreaInfoVO generateIdCardNoAreaCode(String provinceCode, String cityCode, String countyCode) {
        int step = 0;
        if (StringUtils.length(countyCode) != RandomPeopleInfoDataContants.AREA_CODE_LENGTH) {
            if (StringUtils.length(cityCode) == RandomPeopleInfoDataContants.AREA_CODE_LENGTH) {
                step = 3;
            } else if (StringUtils.length(provinceCode) == RandomPeopleInfoDataContants.AREA_CODE_LENGTH) {
                step = 2;
            }
            switch (step) {
                default:
                case 1:
                    IdCardBeginNoConfig provinceConfig = (IdCardBeginNoConfig) getRandomObject(appPropertiesConfig.getIdCardBeginNoProvinceList());
                    provinceCode = provinceConfig.getCode();
                case 2:
                    String provinceCodePrefix = StringUtils.left(provinceCode, RandomPeopleInfoDataContants.PROVINCE_CODE_PREFIX_LENGTH);
                    List<IdCardBeginNoConfig> cityCodeList = appPropertiesConfig.getIdCardBeginNoCityMap().get(provinceCodePrefix);
                    IdCardBeginNoConfig cityConfig = (IdCardBeginNoConfig) getRandomObject(cityCodeList);
                    cityCode = cityConfig.getCode();
                case 3:
                    String cityCodePrefix = StringUtils.left(cityCode, RandomPeopleInfoDataContants.CITY_CODE_PREFIX_LENGTH);
                    List<IdCardBeginNoConfig> countyCodeList = appPropertiesConfig.getIdCardBeginNoCountyMap().get(cityCodePrefix);
                    IdCardBeginNoConfig countyConfig = (IdCardBeginNoConfig) getRandomObject(countyCodeList);
                    countyCode = countyConfig.getCode();
            }
        }
        IdCardBeginNoConfig county = appPropertiesConfig.getIdCardBeginNoAllMap().get(countyCode);

        cityCode = StringUtils.left(countyCode, RandomPeopleInfoDataContants.CITY_CODE_PREFIX_LENGTH);
        cityCode = StringUtils.rightPad(cityCode, RandomPeopleInfoDataContants.AREA_CODE_LENGTH, RandomPeopleInfoDataContants.AREA_CODE_PAD_STR);
        IdCardBeginNoConfig city = appPropertiesConfig.getIdCardBeginNoAllMap().get(cityCode);

        provinceCode = StringUtils.left(countyCode, RandomPeopleInfoDataContants.PROVINCE_CODE_PREFIX_LENGTH);
        provinceCode = StringUtils.rightPad(provinceCode, RandomPeopleInfoDataContants.AREA_CODE_LENGTH, RandomPeopleInfoDataContants.AREA_CODE_PAD_STR);
        IdCardBeginNoConfig province = appPropertiesConfig.getIdCardBeginNoAllMap().get(provinceCode);

        return new IdCardAreaInfoVO(province, city, county);
    }

    /**
     * 根据生日实时计算年龄
     *
     * @param birthday
     * @return
     */
    private Integer calcAge(Date birthday) {
        Integer now = Integer.valueOf(DateFormatUtils.format(new Date(), "yyyyMMdd"));
        Integer birth = Integer.valueOf(DateFormatUtils.format(birthday, "yyyyMMdd"));
        return (now - birth) / 10000;
    }

    /**
     * 生成身份证号尾号
     *
     * @param idCardBegin17
     * @return
     */
    private String generateIdCardTrailingNo(String idCardBegin17) {
        idCardBegin17 = StringUtils.left(idCardBegin17, 17);
        List<String> cArray = Splitter.on(",").omitEmptyStrings().splitToList("7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2");
        List<String> rArray = Splitter.on(",").omitEmptyStrings().splitToList("1,0,X,9,8,7,6,5,4,3,2");
        int result = 0;
        for (int i = 0; i < idCardBegin17.length(); i++) {
            int r1 = Integer.valueOf(cArray.get(i));
            int r2 = Integer.valueOf(StringUtils.substring(idCardBegin17, i, i + 1));
            result += r1 * r2;
        }
        return rArray.get(result % 11);
    }

    /**
     * 生成指定年龄的生日日期
     *
     * @return
     */
    private Date generateBirthday(int age) {
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR) - age;
        int month = random.nextInt(12);
        int date = 1 + random.nextInt(31);
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month);
        calendar.set(Calendar.DATE, date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 生成随机成年人生日，当前日期20岁~60岁
     *
     * @return
     */
    private Date generateRandomAdultBirthday() {
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR) - (20 + random.nextInt(41));
        int month = random.nextInt(12);
        int date = 1 + random.nextInt(31);
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month);
        calendar.set(Calendar.DATE, date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 从list中随机取值
     *
     * @param list
     * @return
     */
    private Object getRandomObject(List<?> list) {
        return list.get(random.nextInt(list.size()));
    }

    @PostConstruct
    public void initialConfig() {
        appPropertiesConfig.initialConfig();
    }

}
